package com.demo.auth.provider;

import com.demo.auth.common.token.SmsCodeAuthenticationToken;
import com.demo.auth.entity.SmsCode;
import lombok.Data;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

/**
 * 手机号登录校验逻辑
 *
 * @author YT
 * @date 2019-06-05
 */
@Data
public class SmsCodeAuthenticationProvider implements AuthenticationProvider {

    private UserDetailsService userDetailsService;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        SmsCodeAuthenticationToken authenticationToken = (SmsCodeAuthenticationToken) authentication;
        String mobile = authentication.getPrincipal().toString();
        checkMobileCode(mobile);
        UserDetails userDetails = userDetailsService.loadUserByUsername(mobile);

        if (userDetails == null) {
            throw new InternalAuthenticationServiceException("无法获取用户信息");
        }

        SmsCodeAuthenticationToken authResult = new SmsCodeAuthenticationToken(userDetails, userDetails.getAuthorities());
        authResult.setDetails(authenticationToken.getDetails());
        return authResult;
    }

    private void checkMobileCode(String mobile) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String inputCode = request.getParameter("smsCode");

        Map<String, Object> mobileCode = (Map<String, Object>) request.getSession().getAttribute("smsCode");
        if (mobileCode == null) {
            throw new BadCredentialsException("未检测到申请短信验证码");
        }

        String applyMobile = (String) mobileCode.get("mobile");
        if (!applyMobile.equals(mobile)) {
            throw new BadCredentialsException("申请短信验证码的手机号码与登录手机号码不一致");
        }

        SmsCode smsCode = (SmsCode) mobileCode.get("code");
        if (smsCode.getCode().equals(inputCode) == false) {
            throw new BadCredentialsException("验证码错误");
        }
    }

    /**
     * 判断 authentication 是不是 MobileCodeAuthenticationToken 的子类或者子接口
     *
     * @param authentication
     * @return
     */
    @Override
    public boolean supports(Class<?> authentication) {
        return SmsCodeAuthenticationToken.class.isAssignableFrom(authentication);
    }
}
